﻿///----------------------------------------------------------------------------
///This is a library of Digital Logic Gates. 
///----------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;


namespace LogicGates
{

    
    /// <summary>
    /// Abstract Class InputDevice.  Just about all components in LogicGates 
    /// will inherit from this base class since all components will have an input
    /// </summary>
    public abstract class InputDevice
    {
        #region Private Variables
        private int[] mArrayOfInputs;
        #endregion

        #region Properties
        /// <summary>
        /// Read-Only Input property for this Input Device.  
        /// </summary>
        public int[] Input { get { return mArrayOfInputs; } }
        #endregion

        #region Constructors

        /// <summary>
        /// Constructor for Input Device
        /// </summary>
        /// <param name="numberOfInputs"> Number of inputs of this device</param>
        public InputDevice(int numberOfInputs)
        {
            mArrayOfInputs = new int[numberOfInputs];
        }
        #endregion

        #region Class Functions

        /// <summary>
        /// Method to set all of the inputs of this device.  
        /// </summary>
        /// <param name="inputValues">Array in input values.  0 and 1 are used for MIPS Project</param>
        public void setInputs(params int[] inputValues)
        {
            for (int i = 0; i < inputValues.Length; i++)
            {
                mArrayOfInputs[i] = inputValues[i];
            }
        }
        #endregion
    }

    #region Basic Logic Gates

    /// <summary>
    /// Abstract Class Gate.  This is a base class that has inputs which are 
    /// are inherited from InputDevice, and a Defined output Property
    /// </summary>
    public abstract class Gate : InputDevice
    {
        #region Constructors
        /// <summary>
        /// Gate Object Constructor
        /// </summary>
        /// <param name="numberOfInputs">Number of inputs of this Gate Object</param>
        protected Gate(int numberOfInputs) : base(numberOfInputs) { }
        #endregion

        #region Properties
        /// <summary>
        /// The output of this gate object.  This is an Abstract Read-Only
        /// property that must be defined by deriving classes.  
        /// </summary>
        public abstract int Output { get; }
        #endregion
    }
    
    /// <summary>
    /// Abstract Single Input Single Output Gate object.  This class has a 
    /// single input which is accessible through a property.  
    /// </summary>
    public abstract class SingleInputSingleOutputGate : Gate
    {
        #region Constructors
        /// <summary>
        /// Constructor for a Single-Input-Single-Output Gate Object
        /// </summary>
        protected SingleInputSingleOutputGate() : base(1) { }
        #endregion

        #region Properties
        /// <summary>
        /// Read-Only property that allows access to the Input Value of this
        /// Single-Input-Single-Output Gate Object
        /// </summary>
        public int Input1 { get { return this.Input[0]; } }
        #endregion
    }
    
    /// <summary>
    /// Abstract Dual Input Single Output Gate object.  This class has 
    /// Dual Inputs which are accessible through a properties.  
    /// </summary>
    public abstract class DualInputSingleOutputGate : Gate
    {
        #region Constructors
        /// <summary>
        /// Constructor for a Dual-Input-Single-Output Gate Object
        /// </summary>
        protected DualInputSingleOutputGate() : base(2) { }
        #endregion

        #region Properties
        /// <summary>
        /// Read and Write Property that exposes the First input of this Gate Object
        /// </summary>
        public int Input1 { get { return this.Input[0]; } set { this.Input[0] = value; } }

        /// <summary>
        /// Read and Write Property that exposes the Second Input of this Gate Object
        /// </summary>
        public int Input2 { get { return this.Input[1]; } set { this.Input[1] = value; } }
        #endregion
    }

    /// <summary>
    /// A Single Input Not Gate 
    /// </summary>
    public sealed class NotGate : SingleInputSingleOutputGate
    {
        #region Class Functions
        /// <summary>
        /// The Output of this Not Gate.  Output = Inversion of the Input.
        /// </summary>
        public override int Output { get { return (this.Input1 ^ 1); } }
        #endregion
    }

    /// <summary>
    /// A Dual Input And Gate
    /// </summary>
    public sealed class AndGate : DualInputSingleOutputGate
    {
        #region Class Functions
        /// <summary>
        /// The Output of this And Gate.
        /// </summary>
        public override int Output { get { return (Input1 & Input2); } }
        #endregion
    }

    /// <summary>
    /// A Dual Input Or Gate
    /// </summary>
    public sealed class OrGate : DualInputSingleOutputGate
    {
        #region Class Functions
        /// <summary>
        /// Output of this Or Gate
        /// </summary>
        public override int Output { get { return (Input1 | Input2); } }
        #endregion
    }

    /// <summary>
    /// A Dual Input Xor Gate
    /// </summary>
    public sealed class XorGate : DualInputSingleOutputGate
    {
        #region Class Functions
        /// <summary>
        /// Output of this Xor Gate.  Output = 1 if Inputs are not Equal
        /// </summary>
        public override int Output { get { return (Input1 ^ Input2); } }
        #endregion
    }

    /// <summary>
    /// A Dual Input Nor Gate.  This object is constructing by combining 
    /// a Not Gate and an Or Gate.
    /// </summary>
    public sealed class NorGate : DualInputSingleOutputGate
    {
        #region Member Variables
        private OrGate mOrGate = new OrGate();
        private NotGate mNotGate = new NotGate();
        #endregion

        #region Class Functions

        /// <summary>
        /// Output of this Nor Gate.  
        /// </summary>
        public override int Output
        {
            get
            {
                mOrGate.setInputs(this.Input1, this.Input2);
                mNotGate.setInputs(mOrGate.Output);
                return mNotGate.Output;
            }
        }
        #endregion
    }

    /// <summary>
    /// A Multi-Input Nor Gate.  Number of inputs is specified at object 
    /// construction
    /// </summary>
    public sealed class NorGateX : Gate
    {
        int mNumberOfInputs;
        #region Constructors

        /// <summary>
        /// Constructor for a Multi-Input Nor Gate
        /// </summary>
        /// <param name="numberOfInputs">Number of inputs for this Nor Gate</param>
        public NorGateX(int numberOfInputs) :base(numberOfInputs) 
        { 
            mNumberOfInputs=numberOfInputs;
        }
        #endregion

        #region Class Functions

        /// <summary>
        /// Output of this Multi-Input Nor Gate Object
        /// </summary>
        public override int Output
        { 
            get 
            {
                int returnValue = 0;

                //Scan through inputs
                for (int i = 0; i < mNumberOfInputs; i++)
                {
                    //if anything anything is 1, set output to 1
                    if (this.Input[i] == 1)
                    {
                        returnValue = 1;
                    }
                }
                //Nor gate, therefore, invert return
                return (returnValue == 1 ? 0 : 1);
            } 
        }
        #endregion
    }

    
    /// <summary>
    /// A Dual Input Nand Gate
    /// </summary>
    public sealed class NandGate : DualInputSingleOutputGate
    {
        #region Member Varibales
        private AndGate mAndGate = new AndGate();
        private NotGate mNotGate = new NotGate();
        #endregion

        #region Class Functions

        /// <summary>
        /// Output of this Nand Gate
        /// </summary>
        public override int Output
        {
            get
            {
                mAndGate.setInputs(this.Input1, this.Input2);
                mNotGate.setInputs(mAndGate.Output);
                return mNotGate.Output;
            }
        }
        #endregion
    }

    /// <summary>
    /// A Dual Input Xnor Gate
    /// </summary>
    public sealed class XnorGate : DualInputSingleOutputGate
    {
        #region Member Variables
        private XorGate mXorGate = new XorGate();
        private NotGate mNotGate = new NotGate();
        #endregion

        #region Class Functions
        /// <summary>
        /// Output of this Xnor Gate
        /// </summary>
        public override int Output
        {
            get
            {
                mXorGate.setInputs(this.Input1, this.Input2);
                mNotGate.setInputs(mXorGate.Output);
                return mNotGate.Output;
            }
        }
        #endregion
    }

    #endregion Basic Logic Gates

    /// <summary>
    /// Multiplexor Object that has a Inputs, a Select and an Output.  
    /// </summary>
    public sealed class Multiplexor:InputDevice
    {
        int mSelect=0;

        /// <summary>
        /// Constructor for a Multiplexor.  Number of input lines is specified at 
        /// object construction.
        /// </summary>
        /// <param name="numberOfInputs">Number of input lines to select </param>
        public Multiplexor(int numberOfInputs) : base(numberOfInputs) { }

        /// <summary>
        /// Read and Write property that allows the Select Line to be Accessed
        /// and Mutated
        /// </summary>
        public int Select { get { return mSelect; } set { mSelect = value; } }

        /// <summary>
        /// Read-only property that allows the Output to be accessed.  This
        /// is the output of the Multiplexor, which is the input that is 
        /// selected at the select line. 
        /// </summary>
        public int Output { get { return this.Input[mSelect]; } }

        /// <summary>
        /// This method gets the input value at the specified input line.
        /// </summary>
        /// <param name="inputNumber">Number of the input line of interest</param>
        /// <returns>The value of the input Line that is specified</returns>
        public int getInput(int inputNumber)
        {
            return this.Input[inputNumber];
        }

    }
    
    #region DigitalCircuits
    
    /// <summary>
    /// Abstract Digital Circuit class which inherits from input device.  
    /// All Digital circuits will derive from this class.  A Clock may be
    /// introduced in the future at this level.
    /// </summary>
    public abstract class DigitalCircuit : InputDevice
    {
        #region Constructors
        protected DigitalCircuit(int numberOfInputs) : base(numberOfInputs) { }
        #endregion
    }

    /// <summary>
    /// A Half Adder
    /// </summary>
    public sealed class HalfAdder : DigitalCircuit
    {
        #region Member Variables
        private XorGate mXorGate = new XorGate();
        private AndGate mAndGate = new AndGate();
        #endregion

        #region Constructors
        /// <summary>
        /// Constructor for a half adder
        /// </summary>
        public HalfAdder() : base(2) { }
        #endregion

        #region Properties
        /// <summary>
        /// The First input of this Half Adder.  Read and Write.
        /// </summary>
        public int A { get { return this.Input[0]; } set { this.Input[0] = value; } }

        /// <summary>
        /// The Second input of this Half Adder.  Read and Write.
        /// </summary>
        public int B { get { return this.Input[1]; } set { this.Input[1] = value; } }    

        /// <summary>
        /// The Sum of the inputs of the Half Adder.  Read Only Property
        /// </summary>
        public int Sum
        {
            get
            {
                mXorGate.setInputs(this.A, this.B);
                return mXorGate.Output;
            }
        }

        /// <summary>
        /// The Carry out of the inputs of the Half Adder.  Read Only Property
        /// </summary>
        public int Carry
        {
            get
            {
                mAndGate.setInputs(this.A, this.B);
                return mAndGate.Output;
            }
        }
        #endregion
    }

    /// <summary>
    /// A Single-Bit Full Adder
    /// </summary>
    public sealed class FullAdderSingleBit : DigitalCircuit
    {

        #region Member Variables
        private XorGate mXorGate1 = new XorGate();
        private XorGate mXorGate2 = new XorGate();
        private AndGate mAndGate1 = new AndGate();
        private AndGate mAndGate2 = new AndGate();
        private OrGate mOrGate1 = new OrGate();
        #endregion

        #region Constructors
        /// <summary>
        /// Constructor for a Single-Bit Full Adder Object.  This object has
        /// 3 Inputs- A, B, Carry In
        /// 2 Outputs- Sum, Carry Out
        /// </summary>
        public FullAdderSingleBit() : base(3) { }
        #endregion

        #region Properties
        /// <summary>
        /// The First Input of this Single-Bit Full Adder.  Read and Write.
        /// </summary>
        public int A { get { return this.Input[0]; } set { this.Input[0] = value; } }

        /// <summary>
        /// The Second Input of this Single-Bit Full Adder.  Read and Write.
        /// </summary>
        public int B { get { return this.Input[1]; } set { this.Input[1] = value; } }

        /// <summary>
        /// The Carry In of this Single-Bit Full Adder.  Read and Write.
        /// </summary>
        public int CarryIn { get { return this.Input[2]; } set { this.Input[2] = value; } }

        /// <summary>
        /// The Sum of the inputs of this Single-Bit Full Adder
        /// </summary>
        public int Sum
        {
            get
            {
                mXorGate1.setInputs(this.A, this.B);
                mXorGate2.setInputs(mXorGate1.Output, this.CarryIn);

                return mXorGate2.Output;
            }
        }

        /// <summary>
        /// The Carry Out of the inputs of this Single-Bit Full Adder
        /// </summary>
        public int CarryOut
        {
            get
            {
                mAndGate1.setInputs(mXorGate1.Output, this.CarryIn);
                mAndGate2.setInputs(this.A, this.B);
                mOrGate1.setInputs(mAndGate1.Output, mAndGate2.Output);
                return mOrGate1.Output;
            }
        }
        #endregion
    }

    /// <summary>
    /// A One-Bit Alu Object.  This Alu can Perform AND, OR, ADD, SUB 
    /// of the Inputs. Operations are performed based on the Op-Code
    /// input. 
    /// Opcode and Operations:
    ///         0- AND 
    ///         1- OR
    ///         2- ADD/SUB.  
    /// For Addition- Carry In and B-Invert are 0. 
    /// For Subtraction- CarryIn and B-Invert are 1. 
    /// </summary>
    public sealed class AluOneBit : DigitalCircuit
    {
        #region Member Variables
        int mBInvert = 0;
        int mCarryIn = 0;
        int mOpCode = 0;

        private FullAdderSingleBit mFullAdder1 = new FullAdderSingleBit();
        private AndGate mAndGate1 = new AndGate();
        private OrGate mOrGate1 = new OrGate();
        private NotGate mNotGate1 = new NotGate();
        private Multiplexor mMultiplexor1 = new Multiplexor(2);
        private Multiplexor mMultiplexor2 = new Multiplexor(3);
        #endregion

        #region Properties

        /// <summary>
        /// The First Input of this One Bit ALU.  Read and Write.
        /// </summary>
        public int A { get { return this.Input[0]; } set { this.Input[0] = value; } }

        /// <summary>
        /// The Second Input of this One Bit ALU.  Read and Write.  
        /// </summary>
        public int B { get { return this.Input[1]; } set { this.Input[1] = value; } }

        /// <summary>
        /// The B-Invert line of this One Bit ALU.  Read and Write.  
        /// </summary>
        public int bInvert { get { return this.mBInvert; } set { this.mBInvert = value; } }

        /// <summary>
        /// The CarryIn of this One Bit ALU.  Read and Write.
        /// </summary>
        public int carryIn { get { return this.mCarryIn; } set { this.mCarryIn = value; } }

        /// <summary>
        /// The OpCode Line of this One Bit ALU.  Read and Write.
        /// </summary>
        public int opCode { get { return this.mOpCode; } set { this.mOpCode = value; } }

        /// <summary>
        /// The Carry Out of this One Bit ALU.  This is the Carry Out Value 
        /// of the Inputs of this One Bit ALU.
        /// </summary>
        public int carryOut
        {
            get
            {
                mNotGate1.setInputs(this.B);
                mMultiplexor1.setInputs(this.B, mNotGate1.Output);
                mMultiplexor1.Select = this.bInvert;

                mFullAdder1.setInputs(this.A, mMultiplexor1.Output, this.carryIn);

                return mFullAdder1.CarryOut;
            }
        }

        /// <summary>
        /// The result of this One Bit ALU after the specified OpCode operation
        /// is performed. 
        /// </summary>
        public int result
        {
            get
            {
                //Set Up B Branch
                mNotGate1.setInputs(this.B);
                mMultiplexor1.setInputs(this.B, mNotGate1.Output);
                mMultiplexor1.Select = this.bInvert;

                //Set Up Full Adder Inputs
                mFullAdder1.setInputs(this.A, mMultiplexor1.Output, this.carryIn);

                //Set Up Smllaer Gates
                mAndGate1.setInputs(this.A, mMultiplexor1.Output);
                mOrGate1.setInputs(this.A, mMultiplexor1.Output);

                //Set up Final Gate Section
                mMultiplexor2.setInputs(mAndGate1.Output, mOrGate1.Output, mFullAdder1.Sum);
                mMultiplexor2.Select = this.opCode;

                return mMultiplexor2.Output;
            }
        }
        #endregion

        #region Constructors
        public AluOneBit() : base(2) { }
        #endregion

    }

    /// <summary>
    /// An X-Bit ALU Object.  The Number of Bits is specified at object 
    /// construction.  This ALU can perform AND, OR, ADD, SUB of the inputs.  
    /// Operations are performed based on the Op-Code.  
    /// Opcode and Operations:
    ///         0- AND 
    ///         1- OR
    ///         2- ADD/SUB.  
    /// For Addition- Carry In and B-Invert are 0. 
    /// For Subtraction- CarryIn and B-Invert are 1. 
    /// </summary>
    public sealed class AluXBit : DigitalCircuit
    {

        #region Member Variables
        int mBInvert = 0;
        int mCarryIn = 0;
        int mOpCode = 0;
        int mNumberOfBits = 0;
        int mCarryOut = 0;

        private List<AluOneBit> mAluArray;
        private NorGateX norGate1;
        #endregion

        #region Properties

        /// <summary>
        /// The First Input bus of this ALU Object.  The Bus is a Series of Inputs.
        /// </summary>
        public bus A
        {
            get
            {
                bus aInputBus = new bus(mNumberOfBits);
                norGate1 = new NorGateX(mNumberOfBits);
                for (int i = 0; i < mNumberOfBits; i++)
                {
                    aInputBus.setBusLocation(i, mAluArray[i].A);
                }
                return aInputBus;
            }
            set
            {
                for (int i = 0; i < mNumberOfBits; i++)
                {
                    mAluArray[i].A = value.getBusLocation(i);
                }
            }
        }

        /// <summary>
        /// The Second Input of this ALU Object.  The Bus is a series of inputs.
        /// </summary>
        public bus B
        {
            get
            {
                bus bInputBus = new bus(mNumberOfBits);


                for (int i = 0; i < mNumberOfBits; i++)
                {
                    bInputBus.setBusLocation(i, mAluArray[i].B);
                }
                return bInputBus;
            }
            set
            {
                for (int i = 0; i < mNumberOfBits; i++)
                {
                    mAluArray[i].B = value.getBusLocation(i);
                }   
            }
        }

        /// <summary>
        /// The Result of the Inputs, after the operation specified by the 
        /// opcode is performed. When accessed, this property will propagate
        /// the input values throughout all of the digital components to
        /// determine the output values. 
        /// </summary>
        public bus result
        {
            get
            {
            
                this.propagateAluXBit();

                bus result = new bus(mNumberOfBits);

                for (int i = 0; i < mNumberOfBits; i++)
                {
                    result.setBusLocation(i, mAluArray[i].result);
                }
                
                //*NOTE NEED TO DO THIS TWICE FOR SOME REASON*//
                this.propagateAluXBit();
                for (int i = 0; i < mNumberOfBits; i++)
                {
                    result.setBusLocation(i, mAluArray[i].result);
                }
                //*NOTE NEEDED TO DO THIS PART TWICE FOR SOME REASON*//
                return result;
            }
        }

        /// <summary>
        /// The Carry out of the inputs of this ALU
        /// </summary>
        public int carryOut
        {
            get
            {
                this.propagateAluXBit();
                return mAluArray[mNumberOfBits - 1].carryOut;
            }
        }

        /// <summary>
        /// The Zero Flag of this ALU.  This property will propagate the inputs
        /// through all of the digital components to derive its value.
        /// </summary>
        public int zero
        {
            get
            {
                this.propagateAluXBit();

                int[] norInputArray = new int[mNumberOfBits];

                for (int i = 0; i < mNumberOfBits; i++)
                {
                    norInputArray[i] = mAluArray[i].result;
                }
                //Determine Zero
                norGate1.setInputs(norInputArray);

                return norGate1.Output;
            }
        }

        /// <summary>
        /// This is the Overflow flag of this ALU.  It will be set if overflow
        /// has occured.  This flag performs logic only on the Highest Order
        /// Bit of Inputs and Results, since that is the sign bit
        /// </summary>
        public int overflow
        {
            get
            {
                int overflowValue = 0;

                this.propagateAluXBit();

                int bitA, bitB, bitSign;

                bitA = mAluArray[mNumberOfBits - 1].A;
                bitB = mAluArray[mNumberOfBits - 1].B;
                bitSign = mAluArray[mNumberOfBits - 1].result;

                //Addition- BInvert = 0
                if (this.bInvert != 1)
                {
                    //If the sign bits of operands are the same, but result is different then Overflow has occured
                    if (((bitA == 1) && (bitB == 1) && (bitSign == 0)) || ((bitA == 0) && (bitB == 0) && (bitSign == 1)))
                    {
                        overflowValue = 1;
                    }
                }
                //Subtraction- BInvert = 1
                else
                {
                    //If the operands have different sign bits and the result bit is different from the sign of operand A,
                    //then Overflow has occured
                    if (((bitA == 1) && (bitB == 0) && (bitSign == 0)) || ((bitA == 0) && (bitB == 1) && (bitSign == 1)))
                    {
                        overflowValue = 1;
                    }
                }
                return overflowValue;
            }
        }

        /// <summary>
        /// The B-Inverty Property of this ALU Object.  Read and Write.
        /// </summary>
        public int bInvert { get { return this.mBInvert; } set { this.mBInvert = value; } }

        /// <summary>
        /// The Carry In Property of this ALU Object.  Read and Write. 
        /// </summary>
        public int carryIn { get { return this.mCarryIn; } set { this.mCarryIn = value; } }

        /// <summary>
        /// The Opcode Property of this ALU Object.  Read and Write.  
        /// 0-AND
        /// 1-OR
        /// 2-ADD (CarryIn=0, BInvert =0), or SUB (CarryIn=1, BInvert=1)
        /// </summary>
        public int opCode { get { return this.mOpCode; } set { this.mOpCode = value; } }
        


        #endregion 

        #region Constructors

        /// <summary>
        /// Constructors for an X-Bit ALU
        /// </summary>
        /// <param name="numberOfBits">The Size of the input Buses</param>
        public AluXBit(int numberOfBits) : base(numberOfBits) 
        {
            mNumberOfBits = numberOfBits;

            mAluArray = new List<AluOneBit>(mNumberOfBits);
            for (int i = 0; i < mNumberOfBits; i++)
            {
                mAluArray.Add(new AluOneBit());
            }
        }
        #endregion 

        #region Object Methods

        /// <summary>
        /// This Method will propagate all of the inputs through the digital 
        /// components to derive the output values for Result, Zero, CarryOut,
        /// Overflow.
        /// </summary>
        private void propagateAluXBit()
        {
            //Initialize All One Bit ALUs
            for (int i = 0; i < mNumberOfBits; i++)
            {
                mAluArray[i].opCode = this.mOpCode;
                mAluArray[i].bInvert = this.mBInvert;
                if (i == 0)
                {
                    mAluArray[i].carryIn = this.mCarryIn;   
                }
                else
                {
                    mAluArray[i].carryIn = mAluArray[i - 1].carryOut;
                }   
            }
        }
        #endregion
    }
    #endregion DigitalCircuits

    /// <summary>
    /// A Bus Object.  A bus is used to group a series of input values together.  
    /// A Bus should contain only 1's and 0's, since those are the values that 
    /// exist in digital logic (high, low).
    /// </summary>
    public class bus
    {
        private int mBusSize = 0;
        private int[] mBus;

        /// <summary>
        /// Constructor for a Bus Object
        /// </summary>
        /// <param name="busSize">The Size, in bits, of this bus</param>
        public bus(int busSize)
        {
            mBusSize = busSize;
            mBus = new int[busSize];
        }

        /// <summary>
        /// This function will set a bus to the specified number.  This method
        /// takes in a Decimal Number and converts it to a binary representation
        /// and sets it to the bus.  The bus will pad left with zeroes up to
        /// the size of the bus.
        /// </summary>
        /// <param name="decimalNumber"></param>
        public void setBus(int decimalNumber)
        {
            string binary = Convert.ToString(decimalNumber, 2).PadLeft(mBusSize,'0');

            binary = binary.Substring((binary.Length - mBusSize), mBusSize);
            int counter = mBusSize - 1;
            for (int i = 0; i < mBusSize; i++)
            {
                
                mBus[i] = (int)Char.GetNumericValue(binary[counter]);
                counter--;
            }    
        }

        /// <summary>
        /// This method is used to modify the value at a specific bit location
        /// in the bus. 
        /// </summary>
        /// <param name="location">The Bit location to mdify</param>
        /// <param name="value">the Value to modify to</param>
        public void setBusLocation(int location, int value)
        {
            mBus[location] = value;
        }

        /// <summary>
        /// This method returns an array of the bus values
        /// </summary>
        /// <returns></returns>
        public int[] getBus()
        {
            return mBus;
        }

        /// <summary>
        /// This method returns the bus value as a Decimal Number
        /// </summary>
        /// <returns></returns>
        public int getBusDecimal()
        {
            int decimalFormNumber;
            string decimalFormString = this.ToString();
            
            if (decimalFormString[0].Equals('1'))
            {
                //Since the String is in 2's Complement Form, we need to change it back to regular
                string smallerString = decimalFormString.Substring(1, decimalFormString.Length - 1);
                smallerString = twosComplement(smallerString);
                decimalFormNumber = -(Convert.ToInt32(smallerString, 2));
            }
            else
            {
                decimalFormNumber = Convert.ToInt32(decimalFormString, 2);
            }
            
            //decimalFormNumber = Convert.ToInt32(decimalFormString, 2);

            return decimalFormNumber;

        }

        /// <summary>
        /// This method returns the value of a specific bit in the bus
        /// </summary>
        /// <param name="location">The Bit Value of Interest</param>
        /// <returns></returns>
        public int getBusLocation(int location)
        {
            return mBus[location];
        }

        /// <summary>
        /// This method returns the bus value as a binary string. 
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            string returnString="";

            //Note This method flips the bus bits, since they are stored backwards internally
            for (int i = mBusSize-1; i >=0; i--)
            {
                returnString += string.Format("{0}", mBus[i]);
            }
            return returnString;
        }

        /// <summary>
        /// This is a helper function that returns the twos-complement of the 
        /// binary input string.
        /// </summary>
        /// <param name="inputString">Binary String to be twos-complemented</param>
        /// <returns></returns>
        public string twosComplement(string inputString)
        {
            string returnString="";
            int carryIn=0;
            int carryOut=1;
            //Invert All Bits
            for (int i = inputString.Length-1; i >=0; i--)
            {
                carryIn=carryOut;
                if(inputString[i].Equals('0') && (carryIn==0))
                {
                    returnString= '1'+returnString;
                    carryOut=0;
                }
                else if(inputString[i].Equals('0') && (carryIn==1))
                {
                    returnString= '0'+returnString;
                    carryOut=1;
                }
                else if(inputString[i].Equals('1') &&(carryIn==0))
                {
                    returnString='0'+returnString;
                    carryOut = 0;
                }
                else
                {
                    returnString='1'+returnString;
                    carryOut = 0;
                }
            }
            return returnString;
        }
    }    
}
